package com.mappertodb;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.Assert;

import com.mappertodb.domain.Column;
import com.mappertodb.domain.Table;

/**
 * Mapper文件toDBSql的工具
 * 由mybatis-generator生成的代码，可以通过本工具生成DBsql
 * 
 * @author y
 *
 */
public class MapperToDb {
	
	private static String[] MAPPER_TYPE = {"BIGINT",     "VARCHAR",      "INTEGER", "TIMESTAMP", "SMALLINT", "DOUBLE", "DATE",   "CHAR",        "TINYINT", "DECIMAL", "TIME"};
	private static String[] SQL_TYPE =    {"BIGINT(20)", "VARCHAR(256)", "INT(11)", "TIMESTAMP", "INT(11)",  "DOUBLE", "DATE", "VARCHAR(64)", "INT(3)",  "DECIMAL", "TIME"};
	
	//主键是否自增长
	private static Boolean AUTO_INCREMENT = false;
	//扫描目录
	private static String SCAN_PATH = "C:\\Users\\y\\Desktop\\temp\\dao";
	//生成sql文件的目录
	private static String SQL_PATH = "C:\\Users\\y\\Desktop\\temp\\sql.txt";
	
	public static void main(String[] args) throws DocumentException {
		//扫描目录下所有文件
	    File file = new File(SCAN_PATH);
	    File[] files = file.listFiles();
	    
	    //获取所有xml
	    ArrayList<String> xmls = new ArrayList<String>();
	    for (int i = 0; i < files.length; i++) {
	        if (files[i].isFile() && files[i].getPath().endsWith(".xml")) {
//	            System.out.println("文     件：" + files[i]);
	        	xmls.add(files[i].toString());
	        }
	    }
		
		//遍历xml，写入sql
	    for(String filePath : xmls) {
	    	File f = new File(filePath);
	    	Table table = analysisMapper(f);
	    	String sql = getDBTableCreateSql(table);
	    	System.out.println("开始写入：" + table.getName());
	    	writeFile(sql, SQL_PATH);
	    }
	    
	    System.out.println("写完了");
		
		
	}
	
	//写入文件
	private static void writeFile(String sql, String filePath) {
		FileOutputStream os = null;
		BufferedOutputStream bos = null;
		try {
			File file = new File(filePath + "test.sql");
			if(!file.exists()) {
				file.createNewFile();
			}
			os = new FileOutputStream(file, true);
			bos = new BufferedOutputStream(os);
			bos.write(sql.getBytes());
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) {
					bos.flush();
					bos.close();
				}
				if(os != null) {
					os.flush();
					os.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}


	/**
	 * 解析mapper ，返回字段list
	 * @param file
	 * @return
	 * @throws DocumentException
	 */
	private static Table analysisMapper(File file) throws DocumentException{
		Table table = new Table();
		
		//读取文件
		SAXReader reader = new SAXReader();
		Document doc = reader.read(file);
		//解析xml获取root元素
		Element root = doc.getRootElement();
		//获取字段dom->resultMap
		Element resultMap = root.element("resultMap");
		
		//表名解析
		String tableName = getTableName(resultMap.attributeValue("type"));
		table.setName(tableName);
		
		List<Column> columnList = new ArrayList<Column>();
		//id主键
		Element id = resultMap.element("id");
		if(id != null) {
			Column primaryKey = new Column();
			primaryKey.setName(id.attributeValue("column"));
			primaryKey.setType(id.attributeValue("jdbcType"));
			primaryKey.setIsPrimary(true);
			columnList.add(primaryKey);
			table.setPrimaryKey(primaryKey);
		}
		
		
		Iterator iterator = resultMap.elementIterator("result");
		while(iterator.hasNext()) {
			Element result = (Element) iterator.next();
			Column column = new Column();
			column.setName(result.attributeValue("column"));
			column.setType(result.attributeValue("jdbcType"));
			columnList.add(column);
		}
		
		table.setColumnList(columnList);
		return table;
	}
	
	/**
	 * 获取创建表的sql
	 * @param table
	 * @return
	 */
	private static String getDBTableCreateSql(Table table) {
		Assert.notNull(table, "qualifiedName不为空");
		Assert.notNull(table.getColumnList(), "table->columnList不为空");
		
		String sql = "\n\n";
		sql += "-- 写入表" + table.getName() + "的结构\n";
		sql += "CREATE TABLE IF NOT EXISTS `" + table.getName() + "` (\n";
		
		//除主键外，其他字段允许null，且默认值为null
		for(Column column : table.getColumnList()) {
			if(column.isPrimaryKey()) {
				sql += "`" + column.getName() + "` " + getSqlType(column.getType()) + " NOT NULL";
				if(AUTO_INCREMENT) {
					sql += " AUTO_INCREMENT";
				}
				sql += ",\n";
			} else {
				sql += "`" + column.getName() + "` " + getSqlType(column.getType()) + " NULL DEFAULT NULL,\n";
			}
		}
		
		//判断是否有主键
		if(table.getPrimaryKey() != null) {
			sql += "PRIMARY KEY (`id`)\n";
		} else {
			sql= sql.substring(0, sql.length()-2);
		}
		
		sql += ")\n";
		
		//table 字符
		sql += "COLLATE='utf8_general_ci'\n";
		//table 引擎
		sql += "ENGINE=InnoDB";
		//结束
		sql +=";";
		
		//打印sql
//		System.out.println(sql);
		return sql;
		
	}
	
	/**
	 * 传入mapper的字段类型， 返回sql的字段类型
	 * @param type
	 * @return
	 */
	private static String getSqlType(String type) {
		String typeSyr = null;
		for(int i = 0 ; i < MAPPER_TYPE.length ; i ++) {
			if(StringUtils.equals(MAPPER_TYPE[i], type)) {
				typeSyr = SQL_TYPE[i];
				break;
			}
		}
		Assert.notNull(typeSyr, "新的类型: " + type + "请添加");
		return typeSyr;
	}


	/**
	 * 获取表名
	 * @param qualifiedName
	 * @return
	 */
	private static String getTableName(String qualifiedName) {
		Assert.notNull(qualifiedName, "qualifiedName不为空");
		
		String temp[] = qualifiedName.split("\\.");
		String name = temp[temp.length-1];
		
		char[] nameChars = name.toCharArray();
		
		StringBuilder res = new StringBuilder();
		for(char item : nameChars) {
			if(Character.isUpperCase(item)) {
				res.append("_" + Character.toLowerCase(item));
			} else {
				res.append(item);
			}
		}
		
		String tableName = res.toString();
		if(tableName.startsWith("_")) {
			tableName = tableName.substring(1);
		}
		
		return tableName;
		
	}
	
}
